﻿using System;
using System.Diagnostics;
using System.IO;
using System.Management;
using System.Net;
using System.Net.NetworkInformation;
using System.Web.Caching;
using System.Web.UI;
using System.Web.UI.WebControls;
using Devv.Core.Utils;
using Microsoft.VisualBasic.Devices;
using SSM.BusinessLayer.Monitors;
using SSM.BusinessLayer.Enums;

namespace SSM.WebReports
{
	public partial class Default_aspx : Page
	{
		#region Variables

		private Computer ThisComputer;
		private Int32 ErrorCount;

		#endregion

		#region Properties

		private Int32 RefreshInterval
		{
			get
			{
				return ConfigUtil.GetConfig("SSM.WebReports.RefreshInterval", 2000);
			}
		}

		private String NetworkIP
		{
			get
			{
				return ConfigUtil.GetConfig("SSM.Network.IP");
			}
		}

		private String NetworkSecondaryIP
		{
			get
			{
				return ConfigUtil.GetConfig("SSM.Network.SecondaryIP", "127.0.0.1");
			}
		}

		private Int32 NetworkSpeedCut
		{
			get
			{
				return ConfigUtil.GetConfig("SSM.Network.SpeedCut", 5);
			}
		}

		private Int32 UptimeStatsCache
		{
			get
			{
				return ConfigUtil.GetConfig("SSM.WebReports.UptimeStats.Cache", 60);
			}
		}

		private String UptimeStatsUrl
		{
			get
			{
				return ConfigUtil.GetConfig("SSM.WebReports.UptimeStats.Url");
			}
		}

		#endregion

		#region Page methods

		protected void Page_Load(Object sender, EventArgs e)
		{
			ThisComputer = new Computer();
			ErrorCount = 0;

			TimerRefreshLoad.Interval = RefreshInterval;

			if (!Page.IsPostBack)
			{
				Page.Title = GetLocalResourceObject("LitPageTitle.Text").ToString();

				TimerRefreshLoad_Tick(null, null);

				GetServerUptime();
				GetServerResources();
				GetUptimeMonitoring();

				ScriptManager.RegisterStartupScript(this, typeof(Page), "GaugeCpuText", "gaugeCpu.label.setText('" + GetLocalResourceObject("GaugeCpu") + "');", true);
				ScriptManager.RegisterStartupScript(this, typeof(Page), "GaugeMemoryText", "gaugeMemory.label.setText('" + GetLocalResourceObject("GaugeMemory") + "');", true);
				ScriptManager.RegisterStartupScript(this, typeof(Page), "GaugeDiskText", "gaugeDisk.label.setText('" + GetLocalResourceObject("GaugeDisk") + "');", true);
				ScriptManager.RegisterStartupScript(this, typeof(Page), "GaugeNetworkText", "gaugeNetwork.label.setText('" + GetLocalResourceObject("GaugeNetwork") + "');", true);
			}
		}

		protected void Page_PreRender(Object sender, EventArgs e)
		{
			PanError.Visible = ErrorCount > 0;
		}

		#endregion

		#region Timer

		protected void TimerRefreshLoad_Tick(Object sender, EventArgs e)
		{
			try
			{
				GetServerInfo();
				GetServerLoad();
				GetServerResources();
			}
			catch (Exception ex)
			{
				GotError(ex);
			}
		}

		#endregion

		#region Server info

		private void GetServerInfo()
		{
			LblInfoServerName.Text = Environment.MachineName;

			GetServerInfo_Cpu();
			GetServerInfo_Memory();
			GetServerInfo_Disk();
			GetServerInfo_OS();
		}

		private void GetServerInfo_Cpu()
		{
			String cpu = String.Empty;

			ManagementClass mc = new ManagementClass("Win32_Processor");
			ManagementObjectCollection processors = mc.GetInstances();

			foreach (ManagementObject obj in processors)
			{
				cpu = "(" + obj.Properties["NumberOfLogicalProcessors"].Value + "x) " + obj.Properties["Name"].Value;
			}

			while (cpu.Contains("  "))
			{
				cpu = cpu.Replace("  ", " ");
			}

			LblInfoProcessor.Text = cpu;
		}

		private void GetServerInfo_Memory()
		{
			Int64 ram = Convert.ToInt64(ThisComputer.Info.TotalPhysicalMemory / 1024);

			LblInfoMemory.Text = IOUtil.GetSizeString(ram) + " " + GetLocalResourceObject("RAM");
		}

		private void GetServerInfo_Disk()
		{
			Int64 capacity = 0;
			DriveInfo[] drives = DriveInfo.GetDrives();

			for (Int32 i = 0; i < drives.Length; i++)
			{
				if (drives[i].IsReady && drives[i].DriveType == DriveType.Fixed)
				{
					capacity += drives[i].TotalSize;
				}
			}

			LblInfoDisk.Text = IOUtil.GetSizeString(capacity / 1024);
		}

		private void GetServerInfo_OS()
		{
			LblInfoPlatform.Text = ThisComputer.Info.OSFullName + " " + Environment.OSVersion.ServicePack;
		}

		#endregion

		#region Server load

		private void GetServerLoad()
		{
			GetCpuLoad();
			GetMemoryLoad();
			GetDiskLoad();
			GetNetworkLoad();
		}

		private void GetCpuLoad()
		{
			PerfMonitor monitor = GetCache("CpuMonitor", new PerfMonitor(PerfMonitorType.CpuLoad));
			Int32 load = Convert.ToInt32(monitor.GetNextValue());

			ScriptManager.RegisterStartupScript(this, typeof(Page), "GaugeCpu", "SetGaugeValue(gaugeCpu, " + load + ");", true);
		}

		private void GetMemoryLoad()
		{
			PerfMonitor monitor = GetCache("MemoryMonitor", new PerfMonitor(PerfMonitorType.MemoryUsage));
			Int32 load = Convert.ToInt32(monitor.GetNextValue());

			ScriptManager.RegisterStartupScript(this, typeof(Page), "GaugeMemory", "SetGaugeValue(gaugeMemory, " + load + ");", true);
		}

		private void GetDiskLoad()
		{
			PerfMonitor monitor = GetCache("DiskMonitor", new PerfMonitor(PerfMonitorType.DiskFreeSpace));
			Int32 load = 100 - Convert.ToInt32(monitor.GetNextValue());

			ScriptManager.RegisterStartupScript(this, typeof(Page), "GaugeDisk", "SetGaugeValue(gaugeDisk, " + load + ");", true);
		}

		private void GetNetworkLoad()
		{
			PerfMonitor monitor = GetCache("NetworkMonitor", null);
			Int64 speed = 10000;

			if (monitor == null)
			{
				String primary = String.Empty;
				String secondary = String.Empty;

				NetworkInterface[] networks = NetworkInterface.GetAllNetworkInterfaces();

				for (Int32 i = 0; i < networks.Length; i++)
				{
					NetworkInterface network = networks[i];

					if (network.NetworkInterfaceType != NetworkInterfaceType.Loopback)
					{
						UnicastIPAddressInformationCollection ips = network.GetIPProperties().UnicastAddresses;

						for (Int32 a = 0; a < ips.Count; a++)
						{
							if (ips[a].Address.ToString() == NetworkIP)
							{
								speed = network.Speed;
								primary = network.Description;
							}
							else if (ips[a].Address.ToString() == NetworkSecondaryIP)
							{
								speed = network.Speed;
								secondary = network.Description;
							}
						}
					}
				}

				if (String.IsNullOrEmpty(primary))
				{
					primary = secondary;
				}

				speed -= speed / 100 * NetworkSpeedCut;

				primary = primary.Replace("/", "_");
				primary = primary.Replace("#", "_");
				primary = primary.Replace("(", "[");
				primary = primary.Replace(")", "]");
				primary = primary.Trim();

				monitor = new PerfMonitor(PerfMonitorType.NetworkBytesPerSecTotal, primary, speed);

				SetCache("NetworkMonitor", monitor);
			}

			if (monitor.Tag == null)
			{
				monitor.Tag = speed;
			}

			Single load = monitor.GetNextValue() / (Convert.ToInt64(monitor.Tag) / 8) * 100;

			ScriptManager.RegisterStartupScript(this, typeof(Page), "GaugeNetwork", "SetGaugeValue(gaugeNetwork, " + load.ToString("0") + ");", true);
		}

		#endregion

		#region Get server resources

		private void GetServerResources()
		{
			GetMemoryAvailable();
			GetTcpInfo();
			GetRunningProcesses();
		}

		private void GetMemoryAvailable()
		{
			String free = IOUtil.GetSizeString(Convert.ToInt64(ThisComputer.Info.AvailablePhysicalMemory / 1024));
			LblFreeMemoryValue.Text = free;

			ScriptManager.RegisterStartupScript(this, typeof(Page), "LabelFreeMemory", "document.getElementById('" + LblFreeMemoryValue.ClientID + "').innerHTML = '" + free + "';", true);
		}

		private void GetTcpInfo()
		{
			PerfMonitor monitor = GetCache("TcpMonitor", new PerfMonitor(PerfMonitorType.TcpConnectionsEstablished));
			Int32 connections = Convert.ToInt32(monitor.GetNextValue());

			LblTcpConnectionsValue.Text = connections.ToString();

			ScriptManager.RegisterStartupScript(this, typeof(Page), "LabelTcpConnections", "document.getElementById('" + LblTcpConnectionsValue.ClientID + "').innerHTML = '" + connections + "';", true);
		}

		private void GetRunningProcesses()
		{
			Int32 count = Process.GetProcesses().Length;

			LblRunningProcessesValue.Text = count.ToString();

			ScriptManager.RegisterStartupScript(this, typeof(Page), "LabelRunningProcesses", "document.getElementById('" + LblRunningProcessesValue.ClientID + "').innerHTML = '" + count + "';", true);
		}

		#endregion

		#region Uptime

		private void GetServerUptime()
		{
			TimeSpan ts = TimeSpan.FromMilliseconds(Environment.TickCount);
			String uptime = String.Empty;

			if (ts.Minutes > 0)
			{
				uptime = ts.Minutes + " " + GetLocalResourceObject("Minutes") + " " + uptime;
			}

			if (ts.Hours > 0)
			{
				uptime = ts.Hours + " " + GetLocalResourceObject("Hours") + " " + uptime;
			}

			if (ts.Days > 0)
			{
				uptime = ts.Days + " " + GetLocalResourceObject("Days") + " " + uptime;
			}

			if (String.IsNullOrEmpty(uptime))
			{
				uptime = GetLocalResourceObject("FewSeconds").ToString();
			}

			LitLastRestartValue.Text = uptime + " " + GetLocalResourceObject("Ago");
		}

		private void GetUptimeMonitoring()
		{
			Object cache = GetCache("UptimeStats");
			String html = String.Empty;

			if (cache == null || String.IsNullOrEmpty(cache.ToString()))
			{
				if (UptimeStatsUrl.Length > 5)
				{
					try
					{
						WebClient client = new WebClient();
						html = client.DownloadString(UptimeStatsUrl);
						SetCache("UptimeStats", html);
					}
					catch (Exception ex)
					{
						GotError(ex);
					}
				}
			}
			else
			{
				html = GetCache("UptimeStats").ToString();
			}

			if (String.IsNullOrEmpty(html))
			{
				PanServiceUptime.Visible = true;
				LitUptimeStats.Visible = false;
			}
			else
			{
				PanServiceUptime.Visible = false;
				LitUptimeStats.Visible = true;
				LitUptimeStats.Text = html;
			}
		}

		#endregion

		#region Cache

		private void SetCache(String key, Object value)
		{
			if (value != null)
			{
				Cache.Add(key, value, null, DateTime.Now.AddMinutes(UptimeStatsCache), TimeSpan.Zero, CacheItemPriority.Default, null);
			}
		}

		private Object GetCache(String key)
		{
			return Cache.Get(key);
		}

		private PerfMonitor GetCache(String key, PerfMonitor monitor)
		{
			Object cached = Cache.Get(key);

			if (cached == null)
			{
				SetCache(key, monitor);
				return monitor;
			}

			return (PerfMonitor)cached;
		}

		#endregion

		#region Errors

		private void GotError(Exception ex)
		{
			Label lbl = new Label();
			lbl.Text = ex.Message;
			PanError.Controls.Add(lbl);

			ErrorCount += 1;
		}

		#endregion
	}
}